﻿

// 元素信息，所有可以在Diagram上展示的内容的父类
function XElement(config) {
    this._name = '';

    this._isHitTestVisible = true;
    this.getHitTestVisible = function () {
        return this._isHitTestVisible;
    }
    this.setHitTestVisible = function (value) {
        this._isHitTestVisible = value;
    }

    // 父元素
    // Parent
    this._parent = null;

    this.children = new Array();

    this.addChild = function (child) {
        this.children.push(child);
        child._parent = this;
    }

    // 元素的大小
    // protected
    this._size = { w: 0, h: 0 };

    // 元素的位置（左上角）
    // protected
    this._pos = { x: 0, y: 0 };

    this.getName = function () {
        return this._name;
    }
    this.setName = function (name) {
        if (this._name != name) {
            this._name = name;
            this.onNameChanged(this._name);
        }
    }

    // #virtual
    this.onNameChanged = function (value) {
    }

    // 获取元素左上角的位置
    // @return:Point
    this.getPos = function () {
        return this._pos;
    }

    // 获取元素的大小，左上角到右下角
    // @return:Size
    this.getSize = function () {
        return this._size;
    }

    // 获取中心点的位置
    // @return:Point
    this.getCenter = function () {
        return {
            x: this._pos.x + this._size.w / 2,
            y: this._pos.y + this._size.h / 2
        };
    }

    // 获取绝对坐标，左上角
    // @return:Point
    this.getAbsolutePos = function () {
        if (this._parent == null) {
            return this.getPos();
        }
        var pAbsolutePos = this._parent.getAbsolutePos();
        return {
            x: pAbsolutePos.x + this._pos.x,
            y: pAbsolutePos.y + this._pos.y
        };
    }

    // 获取绝对的中心点位置
    // @return:Point
    this.getAbsoluteCenter = function () {
        var absolutePos = this.getAbsolutePos();
        return {
            x: absolutePos.x + this._size.w / 2,
            y: absolutePos.y + this._size.h / 2
        };
    }

    // 获取绝对的范围信息
    // @return:Rect{l,t,r,b}
    this.getAbsoluteRect = function () {
        var absolutePos = this.getAbsolutePos();
        return {
            l: absolutePos.x,
            t: absolutePos.y,
            r: absolutePos.x + this._size.w,
            b: absolutePos.y + this._size.h
        };
    }

    // 元素需要更新
    this.update = function () {
        this.onUpdate();
    }

    // 元素更新操作
    // @virtual
    this.onUpdate = function () {

    }

    // 安装到图表上
    // #virtual
    // @diagram:XDiagram
    this.install = function (diagram) {
    }

    // 卸载元素
    // #virtual
    // @diagram:XDiagram
    this.uninstall = function (diagram) {

    }

    // 判断点是否命中了元素对象
    // #virtual
    // @point:Point,坐标信息
    // @return:XHitResult,命中测试结果
    this.hitTest = function (point) {
        var absolutePos = this.getAbsolutePos();
        if (absolutePos.x <= point.x
            && absolutePos.y <= point.y
            && absolutePos.x + this._size.w >= point.x
            && absolutePos.y + this._size.h >= point.y) {
            return new XHitResult(true,
                this,
                { x: point.x - absolutePos.x, y: point.y - absolutePos.y });
        }
        return new XHitResult(false, null, null);
    }
}

// 节点对象，代表流程图中各种信息
function XNode() {
    XElement.apply(this, []);

    // 节点的图形信息
    this._shapes = new Array();
    this._root = null;

    // 添加图形到节点中
    // @shape:图形对象
    // @l:left
    // @t:top
    // @r:right
    // @b:bottom
    // @w:width
    // @h:height
    // @isRoot:bool
    this.addShape = function (shape, l, t, r, b, w, h, isRoot) {
        if (isRoot) {
            this._root = shape;
        }
        shape._position = new XPosition(l, t, r, b, w, h);
        shape.update(this.getAbsolutePos(), this.getSize());

        this._shapes.push(shape);
        return shape;
    }

    this.getRootShape = function () {
        return this._root;
    }

    // 连接关系集合
    this._links = new Array();

    // 添加连接关系
    // @link:XLink连接关系
    this.addLink = function (link) {
        this._links.push(link);
    }

    // 设置左上角的位置
    // @x新的坐标
    // @y
    this.setPos = function (x, y) {
        this._pos.x = x;
        this._pos.y = y;

        var absolutePos = this.getAbsolutePos();
        for (var index = 0; index < this._shapes.length; index++) {
            this._shapes[index].update(absolutePos, this.getSize());
        }

        //reset links position
        this.update();
    }

    // 设置大小
    // @w
    // @h
    this.setSize = function (w, h) {
        this._size.w = w;
        this._size.h = h;

        // 更新元素
        var absolutePos = this.getAbsolutePos();
        for (var index = 0; index < this._shapes.length; index++) {
            this._shapes[index].update(absolutePos, this.getSize());
        }

        this.update();
    }

    // @override
    this.onUpdate = function () {
        // 通知连接线更新
        for (var index = 0; index < this._links.length; index++) {
            this._links[index].update();
        }
    }

    // #override
    this.install = function (diagram) {
        for (var index = 0; index < this._shapes.length; index++) {
            diagram._domEl.appendChild(this._shapes[index]._domEl);
        }
    }

    // #override
    this.uninstall = function (diagram) {
        for (var index = 0; index < this._shapes.length; index++) {
            diagram._domEl.removeChild(this._shapes[index]._domEl);
        }
    }
}

// 流程图中的连接线信息
// @from:XNode,其实的节点
// @to:XNode,目标节点
function XLink(from, to) {
    this._from = from;
    this._to = to;
    this._line = XEngine._gi.createLine();

    this._from.addLink(this);
    this._to.addLink(this);

    XElement.apply(this, [this._line._domEl]);

    // @override
    this.onUpdate = function () {
        // 重新计算连接路径
        this._line.setPoints(this.calcPath());
    }


    this.calcPath = function () {
        //return [this._from.getCenter(), this._to.getCenter()];
        return LinkUtil.calcPath(this._from, this._to);
    }

    // 计算连接路径
    this._line.setPoints(this.calcPath());

    // #override
    this.install = function (diagram) {
        diagram._domEl.appendChild(this._line._domEl);
    }

    // #override
    this.uninstall = function (diagram) {
        diagram._domEl.removeChild(this._line._domEl);
    }

    // #override
    this.hitTest = function (point) {
        return new XHitResult(false, null, null);
    }
}